package com.partsoft.dits.dsm;

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

public class DsmOriginalSQLs {

	// 以注释开头
	public static final String CommentSymbol = "--";

	// 以下是SQL类别
	public static final String DeploySegment = "DEPLOY";

	public static final String UnDeploySegment = "UNDEPLOY";

	public static final String SelectSegment = "SELECT";

	// 触发器
	public static final String TriggerSegment = "TRIGGER";

	public static final String TriggerSegmentInsert = "INSERT";

	public static final String TriggerSegmentDelete = "DELETE";

	public static final String TriggerSegmentUpdate = "UPDATE";

	// 表
	public static final String TableSegment = "TABLE";

	// 校验段
	public static final String ValidateSegment = "VALIDATE";

	// 模式
	public static final String SchemaSegment = "SCHEMA";

	// 视图
	public static final String ViewSegment = "VIEW";

	// 未知段
	public static final String UnknownSegment = "UNKOWN";

	// 监控相关的名称常量
	public class Constants {
		// 缺省的监控表名
		public static final String MonitorLogTable = "DITS.DATA_MONITOR_LOG";

		// 缺省的名字空间
		public static final String MonitorLogNS = "DITS.NSM";

		// 缺省的触发器名称
		public static final String DeleteTrigger = "DITS.DATA_MONITOR_DTG";
		public static final String UpdateTrigger = "DITS.DATA_MONITOR_UTG";
		public static final String InsertTrigger = "DITS.DATA_MONITOR_ITG";

		// 缺省的被监控表名
		public static final String MonitoredTable = "DITS.DATA_MONITOR_TB";
		// 缺省的被监控表数据主键
		public static final String MonitoredDataId = "DATA_ID";
	}

	public String[] deployTriggerDeleteSQLs = null;
	public String[] deployTriggerUpdateSQLs = null;
	public String[] deployTriggerInsertSQLs = null;
	public String[] deployTableSQLs = null;
	public String[] unDeployTriggerDeleteSQLs = null;
	public String[] unDeployTriggerUpdateSQLs = null;
	public String[] unDeployTriggerInsertSQLs = null;
	public String[] unDeployTableSQLs = null;

	public String allSchemaSQL = null;
	public String connValidateSQL = null;
	public String allTableSQL = null;
	public String allTriggerSQL = null;
	public String allViewSQL = null;

	private String sqlSupportProduct;

	private DsmOriginalSQLs() {
	}

	public String getSqlSupportProduct() {
		return sqlSupportProduct;
	}

	public static DsmOriginalSQLs parse(InputStream ios) throws IOException {
		return doParse(ios);
	}

	private static DsmOriginalSQLs doParse(InputStream ios) throws IOException {
		Assert.notNull(ios);
		List<String> deployTriggerDeleteSQLs = new LinkedList<String>();
		List<String> deployTriggerUpdateSQLs = new LinkedList<String>();
		List<String> deployTriggerInsertSQLs = new LinkedList<String>();
		List<String> deployTableSQLs = new LinkedList<String>();
		List<String> unDeployTriggerDeleteSQLs = new LinkedList<String>();
		List<String> unDeployTriggerUpdateSQLs = new LinkedList<String>();
		List<String> unDeployTriggerInsertSQLs = new LinkedList<String>();
		List<String> unDeployTableSQLs = new LinkedList<String>();

		String allSchemaSQL = null;
		String connValidateSQL = null;
		String allTableSQL = null;
		String allTriggerSQL = null;
		String allViewSQL = null;

		StringBuffer lastSQLs = new StringBuffer();
		String lastSQLId = UnknownSegment;
		String lastSQLTpId = UnknownSegment;

		@SuppressWarnings("unchecked")
		List<String> sqlLines = (List<String>) IOUtils.readLines(ios);
		Assert.notEmpty(sqlLines);
		Assert.isTrue(sqlLines.size() > 0, "must have more lines");
		String sqlSupportProduct = sqlLines.get(0).trim().substring(CommentSymbol.length());

		for (int i = 1; i < sqlLines.size(); i++) {
			String sqlLine = sqlLines.get(i);
			String oSqlLine = sqlLine;
			sqlLine = StringUtils.trimLeadingWhitespace(sqlLine);
			if (sqlLine.startsWith(CommentSymbol)) {
				sqlLine = StringUtils.trimLeadingWhitespace(sqlLine.substring(CommentSymbol.length()));
				if (sqlLine.startsWith(DeploySegment)) {
					String newLastSQLId = UnknownSegment;
					sqlLine = StringUtils.trimLeadingWhitespace(sqlLine.substring(DeploySegment.length()));
					if (sqlLine.startsWith(TableSegment)) {
						newLastSQLId = TableSegment;
					} else if (sqlLine.startsWith(TriggerSegment)) {
						sqlLine = StringUtils.trimLeadingWhitespace(sqlLine.substring(TriggerSegment.length()));
						if (sqlLine.startsWith(TriggerSegmentInsert)) {
							newLastSQLId = TriggerSegmentInsert;
						} else if (sqlLine.startsWith(TriggerSegmentDelete)) {
							newLastSQLId = TriggerSegmentDelete;
						} else if (sqlLine.startsWith(TriggerSegmentUpdate)) {
							newLastSQLId = TriggerSegmentUpdate;
						}
					}
					if (!UnknownSegment.equals(newLastSQLId)) {
						String txtLastSQL = StringUtils.trimWhitespace(lastSQLs.toString());
						if (StringUtils.hasText(txtLastSQL)) {
							if (DeploySegment.equals(lastSQLTpId)) {
								if (TriggerSegmentInsert.equals(lastSQLId)) {
									deployTriggerInsertSQLs.add(lastSQLs.toString());
								} else if (TriggerSegmentUpdate.equals(lastSQLId)) {
									deployTriggerUpdateSQLs.add(lastSQLs.toString());
								} else if (TriggerSegmentDelete.equals(lastSQLId)) {
									deployTriggerDeleteSQLs.add(lastSQLs.toString());
								} else if (TableSegment.equals(lastSQLId)) {
									deployTableSQLs.add(lastSQLs.toString());
								}
							} else if (UnDeploySegment.equals(lastSQLTpId)) {
								if (TriggerSegmentInsert.equals(lastSQLId)) {
									unDeployTriggerInsertSQLs.add(lastSQLs.toString());
								} else if (TriggerSegmentUpdate.equals(lastSQLId)) {
									unDeployTriggerUpdateSQLs.add(lastSQLs.toString());
								} else if (TriggerSegmentDelete.equals(lastSQLId)) {
									unDeployTriggerDeleteSQLs.add(lastSQLs.toString());
								} else if (TableSegment.equals(lastSQLId)) {
									unDeployTableSQLs.add(lastSQLs.toString());
								}
							} else if (SelectSegment.equals(lastSQLTpId)) {
								if (TableSegment.equals(lastSQLId)) {
									allTableSQL = lastSQLs.toString();
								} else if (ValidateSegment.equals(lastSQLId)) {
									connValidateSQL = lastSQLs.toString();
								} else if (SchemaSegment.equals(lastSQLId)) {
									allSchemaSQL = lastSQLs.toString();
								} else if (TriggerSegment.equals(lastSQLId)) {
									allTriggerSQL = lastSQLs.toString();
								} else if (ViewSegment.equals(lastSQLId)) {
									allViewSQL = lastSQLs.toString();
								}
							}
						}
						lastSQLTpId = DeploySegment;
						lastSQLId = newLastSQLId;
						lastSQLs = new StringBuffer();
					} else {
						lastSQLs.append(oSqlLine).append("\n");
					}
				} else if (sqlLine.startsWith(DsmOriginalSQLs.UnDeploySegment)) {
					sqlLine = StringUtils.trimLeadingWhitespace(sqlLine.substring(UnDeploySegment.length()));
					String newLastSQLId = UnknownSegment;
					if (sqlLine.startsWith(TableSegment)) {
						newLastSQLId = TableSegment;
					} else if (sqlLine.startsWith(TriggerSegment)) {
						sqlLine = StringUtils.trimLeadingWhitespace(sqlLine.substring(TriggerSegment.length()));
						if (sqlLine.startsWith(TriggerSegmentInsert)) {
							newLastSQLId = TriggerSegmentInsert;
						} else if (sqlLine.startsWith(TriggerSegmentDelete)) {
							newLastSQLId = TriggerSegmentDelete;
						} else if (sqlLine.startsWith(TriggerSegmentUpdate)) {
							newLastSQLId = TriggerSegmentUpdate;
						}
					}
					if (!UnknownSegment.equals(newLastSQLId)) {
						String txtLastSQL = StringUtils.trimWhitespace(lastSQLs.toString());
						if (StringUtils.hasText(txtLastSQL)) {
							if (DeploySegment.equals(lastSQLTpId)) {
								if (TriggerSegmentInsert.equals(lastSQLId)) {
									deployTriggerInsertSQLs.add(lastSQLs.toString());
								} else if (TriggerSegmentUpdate.equals(lastSQLId)) {
									deployTriggerUpdateSQLs.add(lastSQLs.toString());
								} else if (TriggerSegmentDelete.equals(lastSQLId)) {
									deployTriggerDeleteSQLs.add(lastSQLs.toString());
								} else if (TableSegment.equals(lastSQLId)) {
									deployTableSQLs.add(lastSQLs.toString());
								}
							} else if (UnDeploySegment.equals(lastSQLTpId)) {
								if (TriggerSegmentInsert.equals(lastSQLId)) {
									unDeployTriggerInsertSQLs.add(lastSQLs.toString());
								} else if (TriggerSegmentUpdate.equals(lastSQLId)) {
									unDeployTriggerUpdateSQLs.add(lastSQLs.toString());
								} else if (TriggerSegmentDelete.equals(lastSQLId)) {
									unDeployTriggerDeleteSQLs.add(lastSQLs.toString());
								} else if (TableSegment.equals(lastSQLId)) {
									unDeployTableSQLs.add(lastSQLs.toString());
								}
							} else if (SelectSegment.equals(lastSQLTpId)) {
								if (TableSegment.equals(lastSQLId)) {
									allTableSQL = lastSQLs.toString();
								} else if (ValidateSegment.equals(lastSQLId)) {
									connValidateSQL = lastSQLs.toString();
								} else if (SchemaSegment.equals(lastSQLId)) {
									allSchemaSQL = lastSQLs.toString();
								} else if (TriggerSegment.equals(lastSQLId)) {
									allTriggerSQL = lastSQLs.toString();
								} else if (ViewSegment.equals(lastSQLId)) {
									allViewSQL = lastSQLs.toString();
								}
							}
						}
						lastSQLTpId = UnDeploySegment;
						lastSQLId = newLastSQLId;
						lastSQLs = new StringBuffer();
					} else {
						lastSQLs.append(oSqlLine).append("\n");
					}
				} else if (sqlLine.startsWith(SelectSegment)) {
					String newLastSQLId = UnknownSegment;
					sqlLine = StringUtils.trimLeadingWhitespace(sqlLine.substring(SelectSegment.length()));
					if (sqlLine.startsWith(SchemaSegment)) {
						newLastSQLId = SchemaSegment;
					} else if (sqlLine.startsWith(TableSegment)) {
						newLastSQLId = TableSegment;
					} else if (sqlLine.startsWith(ValidateSegment)) {
						newLastSQLId = ValidateSegment;
					} else if (sqlLine.startsWith(TriggerSegment)) {
						newLastSQLId = TriggerSegment;
					} else if (sqlLine.startsWith(ViewSegment)) {
						newLastSQLId = ViewSegment;
					}
					if (!UnknownSegment.equals(newLastSQLId)) {
						String txtLastSQL = StringUtils.trimWhitespace(lastSQLs.toString());
						if (StringUtils.hasText(txtLastSQL)) {
							if (DeploySegment.equals(lastSQLTpId)) {
								if (TriggerSegmentInsert.equals(lastSQLId)) {
									deployTriggerInsertSQLs.add(lastSQLs.toString());
								} else if (TriggerSegmentUpdate.equals(lastSQLId)) {
									deployTriggerUpdateSQLs.add(lastSQLs.toString());
								} else if (TriggerSegmentDelete.equals(lastSQLId)) {
									deployTriggerDeleteSQLs.add(lastSQLs.toString());
								} else if (TableSegment.equals(lastSQLId)) {
									deployTableSQLs.add(lastSQLs.toString());
								}
							} else if (UnDeploySegment.equals(lastSQLTpId)) {
								if (TriggerSegmentInsert.equals(lastSQLId)) {
									unDeployTriggerInsertSQLs.add(lastSQLs.toString());
								} else if (TriggerSegmentUpdate.equals(lastSQLId)) {
									unDeployTriggerUpdateSQLs.add(lastSQLs.toString());
								} else if (TriggerSegmentDelete.equals(lastSQLId)) {
									unDeployTriggerDeleteSQLs.add(lastSQLs.toString());
								} else if (TableSegment.equals(lastSQLId)) {
									unDeployTableSQLs.add(lastSQLs.toString());
								}
							} else if (SelectSegment.equals(lastSQLTpId)) {
								if (TableSegment.equals(lastSQLId)) {
									allTableSQL = lastSQLs.toString();
								} else if (ValidateSegment.equals(lastSQLId)) {
									connValidateSQL = lastSQLs.toString();
								} else if (SchemaSegment.equals(lastSQLId)) {
									allSchemaSQL = lastSQLs.toString();
								} else if (TriggerSegment.equals(lastSQLId)) {
									allTriggerSQL = lastSQLs.toString();
								} else if (ViewSegment.equals(lastSQLId)) {
									allViewSQL = lastSQLs.toString();
								}
							}
						}
						lastSQLTpId = SelectSegment;
						lastSQLId = newLastSQLId;
						lastSQLs = new StringBuffer();
					} else {
						lastSQLs.append(oSqlLine).append("\n");
					}
				} else {
					lastSQLs.append(oSqlLine).append("\n");
				}
			} else if (lastSQLs != null) {
				lastSQLs.append(oSqlLine).append("\n");
			}
		}

		if (!UnknownSegment.equals(lastSQLId) && StringUtils.hasText(StringUtils.trimWhitespace(lastSQLs.toString()))) {
			if (DeploySegment.equals(lastSQLTpId)) {
				if (TriggerSegmentInsert.equals(lastSQLId)) {
					deployTriggerInsertSQLs.add(lastSQLs.toString());
				} else if (TriggerSegmentUpdate.equals(lastSQLId)) {
					deployTriggerUpdateSQLs.add(lastSQLs.toString());
				} else if (TriggerSegmentDelete.equals(lastSQLId)) {
					deployTriggerDeleteSQLs.add(lastSQLs.toString());
				} else if (TableSegment.equals(lastSQLId)) {
					deployTableSQLs.add(lastSQLs.toString());
				}
			} else if (UnDeploySegment.equals(lastSQLTpId)) {
				if (TriggerSegmentInsert.equals(lastSQLId)) {
					unDeployTriggerInsertSQLs.add(lastSQLs.toString());
				} else if (TriggerSegmentUpdate.equals(lastSQLId)) {
					unDeployTriggerUpdateSQLs.add(lastSQLs.toString());
				} else if (TriggerSegmentDelete.equals(lastSQLId)) {
					unDeployTriggerDeleteSQLs.add(lastSQLs.toString());
				} else if (TableSegment.equals(lastSQLId)) {
					unDeployTableSQLs.add(lastSQLs.toString());
				}
			} else if (SelectSegment.equals(lastSQLTpId)) {
				if (TableSegment.equals(lastSQLId)) {
					allTableSQL = lastSQLs.toString();
				} else if (ValidateSegment.equals(lastSQLId)) {
					connValidateSQL = lastSQLs.toString();
				} else if (SchemaSegment.equals(lastSQLId)) {
					allSchemaSQL = lastSQLs.toString();
				} else if (TriggerSegment.equals(lastSQLId)) {
					allTriggerSQL = lastSQLs.toString();
				} else if (ViewSegment.equals(lastSQLId)) {
					allViewSQL = lastSQLs.toString();
				}
			}
		}

		Assert.notEmpty(deployTriggerInsertSQLs, "not have create insert trigger sql");
		Assert.notEmpty(deployTriggerUpdateSQLs, "not have create update trigger sql");
		Assert.notEmpty(deployTriggerDeleteSQLs, "not have create delete trigger sql");
		Assert.notEmpty(deployTableSQLs, "not have create table sql");

		Assert.notEmpty(unDeployTriggerInsertSQLs, "not have drop insert trigger sql");
		Assert.notEmpty(unDeployTriggerUpdateSQLs, "not have drop update trigger sql");
		Assert.notEmpty(unDeployTriggerDeleteSQLs, "not have drop delete trigger sql");
		Assert.notEmpty(unDeployTableSQLs, "not have drop table sql");

		Assert.hasText(allSchemaSQL, "not have select schema sql");
		Assert.hasText(allTableSQL, "not have select table sql");
		Assert.hasText(connValidateSQL, "not have validate connection sql");
		Assert.hasText(allTriggerSQL, "not have select trigger sql");
		Assert.hasText(allViewSQL, "not have select view sql");

		Assert.hasText(sqlSupportProduct, "not have primary key for support db product");

		DsmOriginalSQLs info = new DsmOriginalSQLs();
		info.deployTriggerInsertSQLs = deployTriggerInsertSQLs.toArray(new String[0]);
		info.deployTriggerUpdateSQLs = deployTriggerUpdateSQLs.toArray(new String[0]);
		info.deployTriggerDeleteSQLs = deployTriggerDeleteSQLs.toArray(new String[0]);
		info.deployTableSQLs = deployTableSQLs.toArray(new String[0]);

		info.unDeployTriggerInsertSQLs = unDeployTriggerInsertSQLs.toArray(new String[0]);
		info.unDeployTriggerUpdateSQLs = unDeployTriggerUpdateSQLs.toArray(new String[0]);
		info.unDeployTriggerDeleteSQLs = unDeployTriggerDeleteSQLs.toArray(new String[0]);
		info.unDeployTableSQLs = unDeployTableSQLs.toArray(new String[0]);

		info.allSchemaSQL = allSchemaSQL;
		info.allTableSQL = allTableSQL;
		info.connValidateSQL = connValidateSQL;
		info.allTriggerSQL = allTriggerSQL;
		info.allViewSQL = allViewSQL;

		info.sqlSupportProduct = sqlSupportProduct;
		return info;
	}

	@Override
	public String toString() {
		return "DsmSQLInfo [deployTriggerDeleteSQLs=" + Arrays.toString(deployTriggerDeleteSQLs)
				+ ", deployTriggerUpdateSQLs=" + Arrays.toString(deployTriggerUpdateSQLs)
				+ ", deployTriggerInsertSQLs=" + Arrays.toString(deployTriggerInsertSQLs) + ", deployTableSQLs="
				+ Arrays.toString(deployTableSQLs) + ", unDeployTriggerDeleteSQLs="
				+ Arrays.toString(unDeployTriggerDeleteSQLs) + ", unDeployTriggerUpdateSQLs="
				+ Arrays.toString(unDeployTriggerUpdateSQLs) + ", unDeployTriggerInsertSQLs="
				+ Arrays.toString(unDeployTriggerInsertSQLs) + ", unDeployTableSQLs="
				+ Arrays.toString(unDeployTableSQLs) + ", allSchemaSQL=" + allSchemaSQL + ", connValidateSQL="
				+ connValidateSQL + ", allTableSQL=" + allTableSQL + ", sqlSupportProduct=" + sqlSupportProduct + "]";
	}

}
